package com.minelx.sqlstructures.core;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toMap;

public class ResultSetWrapper {
	private final ResultSet resultSet;

	private final ResultColumns resultColumns;

	private ResultSetWrapper(ResultSet resultSet) {
		this.resultSet = resultSet;
		try {
			resultColumns = new ResultColumns(resultSet.getMetaData());
		} catch (SQLException e) {
			throw new RuntimeException("error while fetching meta data.", e);
		}
	}

	public JSONArray toJSON() {
		try {
			JSONArray result = new JSONArray();
			while (resultSet.next()) {
				result.add(resultColumns.columns().stream()
						.collect(toMap(Column::label, column -> column.asText(resultSet))));
			}
			return result;
		} catch (SQLException e) {
			throw new RuntimeException("error while fetching data from result set.", e);
		}
	}

	public int outputToCSVContent(OutputStream outputStream) {
		try {
			return writeThrough0(outputStream);
		} catch (SQLException e) {
			throw new RuntimeException("error while requesting sql query.", e);
		} catch (IOException e) {
			throw new RuntimeException("error while writing file.", e);
		}
	}

	private int writeThrough0(OutputStream outputStream) throws SQLException, IOException {
		// writing title
		outputStream.write(String.join(",", resultColumns.labels()).getBytes(StandardCharsets.UTF_8));

		// writing content
		int lineCounts = 0;
		while (resultSet.next()) {
			// push a line separator
			outputStream.write("\n".getBytes(StandardCharsets.UTF_8));
			// push a line
			outputStream.write(resultColumns.columns().stream()
					.map(column -> column.asText(resultSet))
					.collect(joining(","))
					.getBytes(StandardCharsets.UTF_8));
			// accumulate line counts
			lineCounts++;
		}
		return lineCounts;
	}

	public static ResultSetWrapper from(ResultSet resultSet) {
		return new ResultSetWrapper(resultSet);
	}
}
